import { readonly, ref, shallowRef } from 'vue'
import { useSyncFeeds } from '@/compositions/feed/syncFeeds'
import { FEED_PERMISION } from '@/constant'
import API from '@/http'

/**
 *
 * @param {Function} request 請求函式
 * @param {Object} params 其他額外的參數
 * @param {Number} limit 分頁數量，預設 10
 */
export function useInfinite({ request, params, limit = 10, initDataList = [], onInit, transformer }) {
  let controller = new AbortController()

  const syncFeeds = useSyncFeeds(request)

  // 請求資料清單
  const dataList = ref([...initDataList])

  // 清單之外的資料
  const dataExtra = shallowRef(null)

  // 是否正在請求中
  const loading = ref(false)

  // 沒有更多了，當判斷到回傳資料數量小於 limit 就會被判定為沒有更多資料
  const noMore = ref(initDataList.length !== 0 && initDataList.length % limit !== 0)

  // 任何請求時捕捉到的錯誤訊息
  const errorMsg = ref('')

  let page = Math.ceil(initDataList.length / limit)

  function init(onData) {
    if (!loading.value && !noMore.value && dataList.value.length === 0 && dataExtra.value === null && page === 0) {
      nextPage(function (...args) {
        onInit?.apply(this, args)
        onData?.apply(this, args)
      })
    }
  }

  function refresh({ newRequest = request, newParams = params, newLimit = limit } = {}, onData) {
    reset()
    request = newRequest
    params = newParams
    limit = newLimit
    nextPage(onData)
  }

  function nextPage(onData) {
    if (loading.value) {
      // console.warn('Infinite reqeust is loading, but you still call nextPage() to request.')
      return
    }
    if (noMore.value) {
      // console.warn('Infinite reqeust is no more data, but you still call nextPage() to request.')
      return
    }

    errorMsg.value = ''
    loading.value = true
    page += 1

    const dataListBeforeRequest = dataList.value

    /**
     * 只要是拿視頻或圖片都把商品給過濾掉，限制要求ALL, SUB類的媒體
     */
    let visibleParams = {}
    if ([API.Media.getVideoList, API.Media.getPhotoList].includes(request)) {
      visibleParams = { visible: `${FEED_PERMISION.ALL},${FEED_PERMISION.SUB}` }
    }
    request({
      data: {
        page,
        limit,
        ...visibleParams,
        ...params,
      },
      config: {
        signal: controller.signal,
      },
    })
      .then((data) => {
        // 判斷 dataList.value 的陣列物件和請求送出前暫存的是否一樣
        // 在某些非常快速操作的情況下就算有執行 reset 可能也不會將請求 abort
        if (dataList.value !== dataListBeforeRequest) return

        const [arr, dataListKey] = extractDataList(data)

        if (arr.length < limit) {
          noMore.value = true
        }
        if (!transformer) {
          dataList.value.push(...syncFeeds(arr))
        } else {
          dataList.value.push(...syncFeeds(arr).map((e) => transformer(e)))
        }

        if (onData) {
          onData(data, dataListKey)
        }
      })
      .catch((e) => {
        console.warn(e)
        errorMsg.value = e.message
      })
      .finally(() => {
        loading.value = false
      })
  }

  function reset() {
    if (loading.value) {
      controller.abort()
      controller = new AbortController()
    }
    loading.value = false
    noMore.value = false
    errorMsg.value = ''
    dataList.value = []
    dataExtra.value = null
    page = 0
  }

  function extractDataList(data) {
    if (Array.isArray(data.list)) {
      saveExtraData(data, 'list')
      return [data.list, 'list']
    } else if (Array.isArray(data)) {
      return [data, undefined]
    } else {
      return [[], undefined]
    }
  }

  function saveExtraData(data, dataListKey) {
    const extraDataKeys = Object.keys(data).filter((k) => k !== dataListKey)
    if (extraDataKeys.length > 0) {
      dataExtra.value = extraDataKeys.reduce((a, v) => {
        a[v] = data[v]
        return a
      }, {})
    }
  }

  return {
    dataList,
    dataExtra: readonly(dataExtra),
    loading: readonly(loading),
    noMore: readonly(noMore),
    errorMsg: readonly(errorMsg),
    init,
    refresh,
    nextPage,
    reset,
  }
}
